/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package wumpus.agente;

import java.util.ArrayList;
import java.util.List;
import wumpus.agente.Agente;
import wumpus.ambiente.Ambiente;

/**
 *
 * @author gregorio
 */
public class BaseDeConhecimento {

    public boolean achouOuro = false;
    public boolean temPerigo = false;
    public int pontuacaoGlobal;
    public boolean wumpus = false;
    public boolean poco = false;
    public boolean pocoEWumpus = false;
    public boolean agComOuro = false;
    public List<String> posicoesSeguras;

    public BaseDeConhecimento() {
        posicoesSeguras = new ArrayList<String>();
    }

    /**
     * metodo que verifica se em uma dada posicao existe um wumpus ou poco ou os dois.
     * @param novaPosicao
     * @param ambiente
     * @return
     */
    public boolean temPerigos(String novaPosicao, Ambiente ambiente) {
        boolean aventureiroMorto = false;
        String poco = ambiente.getAmbiente()[Agente.pegaLinha(novaPosicao)][Agente.pegaColuna(novaPosicao)][4];
        String wumpus = ambiente.getAmbiente()[Agente.pegaLinha(novaPosicao)][Agente.pegaColuna(novaPosicao)][3];
        if (poco != null && wumpus != null) {
            temPerigo = aventureiroMorto = true;
            pocoEWumpus = true;
        } else if (poco != null) {//poco
            temPerigo = aventureiroMorto = true;
            this.poco = true;
        } else if (wumpus != null) {//wumpus
            temPerigo = aventureiroMorto = true;
            this.wumpus = true;
        }
        return aventureiroMorto;
    }

    /**
     * método que irá verficar se o agente achou o ouro
     * @param novaPosicao
     * @param ambiente
     * @return
     */
    public boolean encontrouOuro(String novaPosicao, Ambiente ambiente) {
        boolean achouOuro = false;
        String ouro = ambiente.getAmbiente()[Agente.pegaLinha(novaPosicao)][Agente.pegaColuna(novaPosicao)][1];
        if (ouro != null) {
            achouOuro = true;
            this.achouOuro = true;
            agComOuro = true;
            ambiente.getAmbiente()[Agente.pegaLinha(novaPosicao)][Agente.pegaColuna(novaPosicao)][1] = null;
        //metodo para otimizar o ag
//            otimizacaoAG(novaPosicao);
        }
        return achouOuro;
    }

    public void otimizacaoAG(String posicaoDoAG) {
        localizaAG(Agente.pegaLinha(posicaoDoAG), Agente.pegaColuna(posicaoDoAG));
    }

    public void localizaAG(int linha, int coluna) {
        String posicaoAcima = procuraMelhorPosicaoEmCima(linha, coluna);
        String posicaoAbaixo = procuraMelhorPosicaoEmBaixo(linha, coluna);
        String posicaoDireita = procuraMelhorPosicaoDireita(linha, coluna);
        String posicaoEsquerda = procuraMelhorPosicaoEsquerda(linha, coluna);

        procuraPosicaoMaisProximaDeCasaZeroZero(posicaoAcima, posicaoAbaixo, posicaoDireita, posicaoEsquerda);
    }

    public void procuraPosicaoMaisProximaDeCasaZeroZero(String posicaoAcima, String posicaoAbaixo, String posicaoDireita, String posicaoEsquerda) {
        boolean posicaoUpSegura = verificaSeCasaSegura(posicaoAcima);
        boolean posicaoDownSegura = verificaSeCasaSegura(posicaoAbaixo);
        boolean posicaoRightSegura = verificaSeCasaSegura(posicaoDireita);
        boolean posicaoLeftSegura = verificaSeCasaSegura(posicaoEsquerda);


    }

    public boolean verificaSeCasaSegura(String posicao) {
        boolean muitoSegura = false;
        String posicaoSegura = Ambiente.getAmbiente()[Agente.pegaLinha(posicao)][Agente.pegaColuna(posicao)][6];
        if (posicaoSegura != null) {// se for diferente de null e por que a posicao e segura
            muitoSegura = true;
        }
        return muitoSegura;
    }

    public String procuraMelhorPosicaoEmCima(int linha, int coluna) {
        String posicao = "";
        if (linha < Ambiente.getNUMERO_MAXIMO_DE_LINHAS() - 1) {
            posicao = String.valueOf(linha + 1) + "," + String.valueOf(coluna);
        }
        return posicao;
    }

    public String procuraMelhorPosicaoEmBaixo(int linha, int coluna) {
        String posicao = "";
        if (linha > 0) {
            posicao = String.valueOf(linha - 1) + "," + String.valueOf(coluna);
        }
        return posicao;
    }

    public String procuraMelhorPosicaoDireita(int linha, int coluna) {
        String posicao = "";
        if (coluna < Ambiente.getNUMERO_MAXIMO_DE_COLUNAS() - 1) {
            posicao = String.valueOf(linha) + "," + coluna + 1;
        }
        return posicao;
    }

    public String procuraMelhorPosicaoEsquerda(int linha, int coluna) {
        String posicao = "";
        if (coluna > 0) {
            posicao = String.valueOf(linha) + "," + String.valueOf(coluna - 1);
        }
        return posicao;
    }

    /**
     * metodo que verifica se o aventureiro chegou na casa (0,0) com o ouro
     * @param novaPosicao
     * @param ambiente
     * @return true se o aventureiro chegou na casa (0,0) com o ouro
     */
    public boolean verificaChegada(String novaPosicao, Ambiente ambiente) {
        boolean cheguei = false;

        String posicaoAtualDoAventureiro = ambiente.posicaoAtualDoAventureiro(Agente.pegaLinha(novaPosicao), Agente.pegaColuna(novaPosicao));
//        if (posicaoAtualDoAventureiro.equals("0,0") && achouOuro) {
//            cheguei = true;
////            System.out.println("Cheguei em casa são e salvo");
//        }
        if (posicaoAtualDoAventureiro.equals("0,0") && agComOuro) {
            cheguei = true;
        }
        return cheguei;
    }

    /**
     * metodo que imprime todas as posicoes do ambiente, com excecao das posicoes seguras
     * @param ambiente
     */
    public String imprimeAmbiente(Ambiente ambiente) {
        String saidaAmbiente = "";
        for (int i = 0; i < ambiente.getAmbiente().length; i++) {
            for (int j = 0; j < ambiente.getAmbiente().length; j++) {
                for (int z = 0; z < 6; z++) {
                    String s = ambiente.getAmbiente()[i][j][z];
                    if (ambiente.getAmbiente()[i][j][z] != null) {
                        saidaAmbiente += "posicao (" + i + "," + j + ") = " + s + "\n";
                    }
                }
            }
        }
        return saidaAmbiente;
    }

    /**
     * metodo que ira dar continuidade na execucao do metodo main
     * @param main
     * @param novaPosicao
     * @param ambiente
     * @param ag
     * @param posicaoAtualAgente
     * @param perigo
     * @param ouro
     * @param chegouEmCasa
     * @param calculaPontuacao
     */
    public String executaAgente(BaseDeConhecimento main, String novaPosicao, Ambiente ambiente, Agente ag,
            String posicaoAtualAgente, boolean perigo, boolean ouro, boolean chegouEmCasa, int pontuacao) {
        String saidaAcaoAgente = "";
        int linha = ag.pegaLinha(posicaoAtualAgente);
        int coluna = ag.pegaColuna(posicaoAtualAgente);
        String conteudoPosicaoInicial = ambiente.getAmbiente()[linha][coluna][6];
        posicoesSeguras.add(posicaoAtualAgente);
        reconhecerPosicaoSegura(ambiente, ag, conteudoPosicaoInicial, posicaoAtualAgente);
        do {
            String posicaoSegura = ambiente.getAmbiente()[ag.pegaLinha(posicaoAtualAgente)][ag.pegaColuna(posicaoAtualAgente)][6];
            posicaoAtualAgente = ag.fazAgenteCaminhar(novaPosicao);
            ambiente.atualizaAmbiemte(posicaoAtualAgente);
            saidaAcaoAgente += "AGINDO: andei para a casa = " + posicaoAtualAgente + "\n";

            perigo = main.temPerigos(posicaoAtualAgente, ambiente);
            if (!perigo) {//se tiver perigo o ag morre, caso contrario a posicao e segura
                ouro = main.encontrouOuro(novaPosicao, ambiente);
                reconhecerPosicaoSegura(ambiente, ag, posicaoSegura, posicaoAtualAgente);
                if (agComOuro) {
                    chegouEmCasa = main.verificaChegada(novaPosicao, ambiente);
                }
            }
            if (perigo) {
                this.pontuacaoGlobal = calculaPontuacao();
                if (wumpus) {
                    saidaAcaoAgente += "aventureiro morto pelo wumpus ! (" + Agente.pegaLinha(novaPosicao) + "," + Agente.pegaColuna(novaPosicao) + ")" ;
                } else if (poco) {
                    saidaAcaoAgente += "aventureiro morreu pois caiu no poco ! (" + Agente.pegaLinha(novaPosicao) + "," + Agente.pegaColuna(novaPosicao) + ")";
                } else if (pocoEWumpus) {
                    saidaAcaoAgente += "aventureiro morto pelo wumpus e teve seu corpo jogado no poco ! (" + Agente.pegaLinha(novaPosicao) + "," + Agente.pegaColuna(novaPosicao) + ")" ;
                }
                break;
            } else if (ouro) {
                if (achouOuro) {
                    saidaAcaoAgente += "Encontrei e peguei o ouro na casa = (" + Agente.pegaLinha(novaPosicao) + "," + Agente.pegaColuna(novaPosicao) + ")" +
                            "\nvou voltar pra casa feliz da vida.\n";
                }
                this.pontuacaoGlobal = calculaPontuacao();
            } else if (chegouEmCasa) {
                saidaAcaoAgente += "Cheguei em casa são e salvo\n";
                this.pontuacaoGlobal = calculaPontuacao();
                break;
            } else {
                this.pontuacaoGlobal = calculaPontuacao();
            }

            novaPosicao = ag.decidePraOndeAGVai(ambiente.posicaoAtualDoAventureiro(ag.pegaLinha(posicaoAtualAgente), ag.pegaColuna(posicaoAtualAgente)));
        } while (perigo == false || chegouEmCasa == false);
        return saidaAcaoAgente;
    }

    /**
     * Metodo que verifica se uma dada posicao e segura ou nao.
     * Se a posicao em que o ag estiver nao contiver nenhum perigo, ou seja, se ele ainda estiver vivo, entao ela e segura e adicionamos
     * ela a lista de posicoesSeguras.
     * E possivel que o ag ja esteja em uma posicao segura, e para evitar a distribuicao incoerente de posicoes seguras
     * verifica-se a posicaoAtualDoAgente, de modo que se ela for segura desde a geracao do ambiente,
     * chama-se o metodo que verifica se na dada posicao ha outra percepcao, caso NAO haja, entao
     * faremos a distribuicao das casa adjacentes que tambem sao seguras
     * @param ambiente instancia decorrente do ambiente
     * @param ag instancia decorrente do agente
     * @param posicaoSegura posicao contendo a possivel posicao segura
     * @param posicaoAtualAgente posicao atual do aventureiro
     */
    public void reconhecerPosicaoSegura(Ambiente ambiente, Agente ag, String posicaoSegura, String posicaoAtualAgente) {
        int linha = ag.pegaLinha(posicaoAtualAgente);
        int coluna = ag.pegaColuna(posicaoAtualAgente);
        if (posicaoSegura == null) {
            ambiente.getAmbiente()[linha][coluna][6] = ambiente.getPOSICAO_SEGURA();
            if (!posicoesSeguras.contains(linha + "," + coluna)) {
                posicoesSeguras.add(linha + "," + coluna);
            }
        } else {
            verificaTodasPercepcoes(posicaoAtualAgente, ambiente);
        }
    }

    /**
     * Metodo que verifica se a posicao do ag contem alguma percepcao
     * @param posicaoAg posicao do aventureiro
     * @param ambiente instancia decorrente do ambiente
     */
    public void verificaTodasPercepcoes(String posicaoAg, Ambiente ambiente) {
        String brisa = ambiente.getAmbiente()[Agente.pegaLinha(posicaoAg)][Agente.pegaColuna(posicaoAg)][2];
        String fedor = ambiente.getAmbiente()[Agente.pegaLinha(posicaoAg)][Agente.pegaColuna(posicaoAg)][5];
        String posicaoSegura = ambiente.getAmbiente()[Agente.pegaLinha(posicaoAg)][Agente.pegaColuna(posicaoAg)][6];
        if (posicaoSegura == null) {
            if (brisa == null && fedor == null) {//se true entao faz a distribuicao de posicoes seguras
                distribuiPosicoesSeguras(posicaoAg, ambiente);
            } else {
                if (!posicoesSeguras.contains(posicaoAg)) {
                    posicoesSeguras.add(posicaoAg);
                }
            }
        } else {
            distribuiPosicoesSeguras(posicaoAg, ambiente);
        }
    }

    /**
     * Metodo que fara a distribuicao das posicoes seguras de acordo com as percepcoes da posicao do aventureiro
     * @param posicaoAg posicao do aventureiro
     * @param ambiente instancia decorrente do ambiente
     */
    public void distribuiPosicoesSeguras(String posicaoAg, Ambiente ambiente) {
        distribuiPosicaoSeguraCima(ambiente, posicaoAg);
        distribuiPosicaoSeguraBaixo(ambiente, posicaoAg);
        distribuiPosicaoSeguraDireita(ambiente, posicaoAg);
        distribuiPosicaoSeguraEsquerda(ambiente, posicaoAg);
    }

    public void distribuiPosicaoSeguraCima(Ambiente ambiente, String posicaoAg) {
        if (Agente.pegaLinha(posicaoAg) + 1 < Ambiente.getNUMERO_MAXIMO_DE_LINHAS() - 1) {
            int linha = Agente.pegaLinha(posicaoAg) + 1;
            int coluna = Agente.pegaColuna(posicaoAg);
            String posicaoSegura = ambiente.getAmbiente()[linha][coluna][6];
            if (posicaoSegura == null) {
                ambiente.getAmbiente()[linha][coluna][6] = Ambiente.getPOSICAO_SEGURA();
                if (!posicoesSeguras.contains(linha + "," + coluna)) {
                    posicoesSeguras.add(linha + "," + coluna);
                }
            } else {
                if (!posicoesSeguras.contains(linha + "," + coluna)) {
                    posicoesSeguras.add(linha + "," + coluna);
                }
            }
        }
    }

    public void distribuiPosicaoSeguraBaixo(Ambiente ambiente, String posicaoAg) {
        if (Agente.pegaLinha(posicaoAg) - 1 > 0) {
            int linha = Agente.pegaLinha(posicaoAg) - 1;
            int coluna = Agente.pegaLinha(posicaoAg);
            String posicaoSegura = ambiente.getAmbiente()[linha][coluna][6];
            if (posicaoSegura == null) {
                ambiente.getAmbiente()[linha][coluna][6] = Ambiente.getPOSICAO_SEGURA();
                if (!posicoesSeguras.contains(linha + "," + coluna)) {
                    posicoesSeguras.add(linha + "," + coluna);
                }
            } else {
                if (!posicoesSeguras.contains(linha + "," + coluna)) {
                    posicoesSeguras.add(linha + "," + coluna);
                }
            }
        }
    }

    public void distribuiPosicaoSeguraDireita(Ambiente ambiente, String posicaoAg) {
        if (Agente.pegaLinha(posicaoAg) + 1 < Ambiente.getNUMERO_MAXIMO_DE_COLUNAS() - 1) {
            int linha = Agente.pegaLinha(posicaoAg);
            int coluna = Agente.pegaLinha(posicaoAg) + 1;
            String posicaoSegura = ambiente.getAmbiente()[linha][coluna][6];
            if (posicaoSegura == null) {
                ambiente.getAmbiente()[linha][coluna][6] = Ambiente.getPOSICAO_SEGURA();
                if (!posicoesSeguras.contains(linha + "," + coluna)) {
                    posicoesSeguras.add(linha + "," + coluna);
                }
            } else {
                if (!posicoesSeguras.contains(linha + "," + coluna)) {
                    posicoesSeguras.add(linha + "," + coluna);
                }
            }
        }
    }

    public void distribuiPosicaoSeguraEsquerda(Ambiente ambiente, String posicaoAg) {
        if (Agente.pegaLinha(posicaoAg) - 1 > 0) {
            int linha = Agente.pegaLinha(posicaoAg);
            int coluna = Agente.pegaLinha(posicaoAg) - 1;
            String posicaoSegura = ambiente.getAmbiente()[linha][coluna][6];
            if (posicaoSegura == null) {
                ambiente.getAmbiente()[linha][coluna][6] = Ambiente.getPOSICAO_SEGURA();
                if (!posicoesSeguras.contains(linha + "," + coluna)) {
                    posicoesSeguras.add(linha + "," + coluna);
                }
            } else {
                if (!posicoesSeguras.contains(linha + "," + coluna)) {
                    posicoesSeguras.add(linha + "," + coluna);
                }
            }
        }
    }

    /**
     * metodo que confere a calculaPontuacao do aventureiro
     * @param calculaPontuacao
     * @return
     */
    public int calculaPontuacao() {
        if (achouOuro) {
            pontuacaoGlobal -= 1;
            pontuacaoGlobal += 1000;
            achouOuro = false;
        } else if (temPerigo) {
            pontuacaoGlobal -= 1;
            pontuacaoGlobal -= 1000;
            temPerigo = false;
        } else {
            pontuacaoGlobal -= 1;
        }
        return pontuacaoGlobal;
    }
}
